/*
 * ReactionBuilder.cpp
 *
 *  Created on: 21 Aug 2011
 *      Author: Allan
 */

#include "ReactionBuilder.h"

// GeoReact includes
#include "Database.h"
#include "Kinetics/MineralKinetics/MineralKineticsDatabase.h"
#include "Reaction.h"

const Reaction AuxiliarCreateReaction(const ReactionInfo& rinfo, const SpeciesMap& speciesMap);

ReactionBuilder::ReactionBuilder()
{}

ReactionBuilder::ReactionBuilder(const SpeciesMap& speciesMap) :
speciesMap(speciesMap)
{}

const Reaction ReactionBuilder::CreateReaction(const string& species)
{
	if(Database::GetInstance().GetSpeciesInfo(species).HasTag("basis"))
		return CreateTrivialReaction(species);
	
	else if(Database::GetInstance().GetSpeciesInfo(species).HasTag("mineral"))
		return CreateMineralReaction(species);
	
	else 
		return CreatePlainReaction(species);
}

const Reaction ReactionBuilder::CreatePlainReaction(const string& species)
{
	// Get the information data of the reaction whose reactant is the given species
	const ReactionInfo reactionInfo = Database::GetInstance().GetReactionInfo(species);
	
	return AuxiliarCreateReaction(reactionInfo, speciesMap);
}

const Reaction ReactionBuilder::CreateTrivialReaction(const string& species)
{
	ReactionInfo reactionInfo;
	
	reactionInfo.reactant        = species;
	reactionInfo.products        = {species};
	reactionInfo.stoichiometries = {1.0};
	reactionInfo.Ki              = {1.0};  // K = 1
	reactionInfo.Ti              = {25.0}; // T = 25 degC

	return AuxiliarCreateReaction(reactionInfo, speciesMap);
}

const Reaction ReactionBuilder::CreateMineralReaction(const string& species)
{
	// Create the reaction object for the given mineral
	Reaction mineralReaction = CreatePlainReaction(species);
	
	// Look up at the database of mineral kinetics for the given mineral
	optional<MineralKineticsInfo> mineralKineticsInfo = MineralKineticsDatabase::GetInstance().FindMineralKineticsInfo(species);
	
	// If the kinetics information of the minaral was found, create a mineral kinetics intance and set the mineral reaction with it
	if(mineralKineticsInfo)
	{
		// Create the mineral kinetics object of the given mineral
		MineralKinetics mineralKinetics;
		
		// Set the reaction whose the mineral kinetics will be responsible to compute the rates of reaction
		mineralKinetics.SetReaction(mineralReaction);
		
		// Set the mineral mechanisms of the reaction
		mineralKinetics.SetMechanisms(mineralKineticsInfo->mechanisms, speciesMap);

		// Set the specific surface area of the mineral
		mineralKinetics.SetSpecificSurfaceArea(mineralKineticsInfo->specificSurfaceArea);
		
		// Set the kinetics of the mineral reaction
		mineralReaction.SetKinectics(mineralKinetics);
	}
	
	return mineralReaction;
}

const Reaction AuxiliarCreateReaction(const ReactionInfo& rinfo, const SpeciesMap& speciesMap)
{
	// The reaction equation
	ReactionEquation equation(speciesMap);
	
	// Set the reaction equation 
	equation.Set(rinfo.reactant, rinfo.products, rinfo.stoichiometries);
	
	// The equation constant of the reaction
	EquilibriumConstant K(rinfo.Ki, rinfo.Ti);
	
	// Create the reaction object
	Reaction reaction(equation, K);
	
	// Return the reaction object
	return reaction;
}
